package oa.base;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;

import oa.db.DbHelper;
import oa.exception.DaoException;

public class BaseDao<T> {
	protected Connection conn;
	protected PreparedStatement pstmt;
	protected ResultSet rs;
	DbHelper db = new DbHelper();
	private Class clazz;

	public static Logger logger = Logger.getLogger(BaseDao.class);

	public BaseDao() {
		// 初始化
		// 获取T的真正类型
		try {
			clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public Connection getConnection() {
		return db.getConnection();
	}

	/**
	 * 适用于查询
	 * 
	 * @param sql
	 * @param objs
	 * @return
	 * @throws DaoException
	 */
	public List<T> executeQuery(String sql, Object... objs) throws DaoException {
		try {
			conn = getConnection();
			pstmt = conn.prepareStatement(sql);

			for (int i = 0; i < objs.length; i++) {
				pstmt.setObject(i + 1, objs[i]);
			}
			logger.info(pstmt);
			rs = pstmt.executeQuery();
			List list = new ArrayList();

			while (rs.next()) {
				// 创建对应查询的实体
				Object obj = clazz.newInstance();
				// 拿到实体类的字段
				Field[] fields = clazz.getDeclaredFields();
				for (Field field : fields) {
					String fieldName = field.getName();
					String conlumName = fieldName.replaceAll("([A-Z])", "_$1").toLowerCase();// 计算列名
					String methodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
					// 获取set方法
					Method method = clazz.getMethod(methodName, field.getType());

					// 赋值
					if (field.getType() == int.class) {
						method.invoke(obj, rs.getInt(conlumName));
					} else if (field.getType() == Date.class) {
						method.invoke(obj, rs.getTimestamp(conlumName));
					} else {
						method.invoke(obj, rs.getString(conlumName));
					}
				}
				list.add(obj);
			}
			return list;
		} catch (Exception e) {
			throw new DaoException("执行查询失败!", e);
		} finally {
			CloseAll(conn, pstmt, rs);
		}
	}

	/**
	 * 适用于数量查询
	 * @param sql
	 * @param objs
	 * @return
	 * @throws DaoException
	 */
	public int executeIntQuery(String sql, Object... objs) throws DaoException {
		try {
			conn = getConnection();
			pstmt = conn.prepareStatement(sql);

			for (int i = 0; i < objs.length; i++) {
				pstmt.setObject(i + 1, objs[i]);
			}
			logger.info(pstmt);
			rs = pstmt.executeQuery();

			while (rs.next()) {
				return rs.getInt(1);
			}
			return 0;
		} catch (Exception e) {
			throw new DaoException("执行查询失败!", e);
		} finally {
			CloseAll(conn, pstmt, rs);
		}
	}
	/**
	 * 适用于增删改
	 * 
	 * @param sql
	 * @param objs
	 * @return
	 * @throws DaoException
	 */
	public int executeUpdate(String sql, Object... objs) throws DaoException {
		try {
			conn = getConnection();
			pstmt = conn.prepareStatement(sql);
			if (objs != null) {
				for (int i = 0; i < objs.length; i++) {
					pstmt.setObject(i + 1, objs[i]);
				}
			}
			logger.info(pstmt);
			return pstmt.executeUpdate();
		} catch (SQLException e) {
			throw new DaoException("更新操作失败", e);
		} finally {
			CloseAll(conn, pstmt, rs);
		}
	}

	public void CloseAll(Connection conn, PreparedStatement pstmt, ResultSet rs) {
		db.CloseAll(conn, pstmt, rs);
	}
}
